home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / SCSI Samples 1.0 / SCSI Async Sample 06⁄15 ƒ / Src / DoSCSISynchronousIO.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-16  |  7.7 KB  |  231 lines  |  [TEXT/KAHL]

  1. /*                                DoSCSISynchronousIO.c                            */
  2. /*
  3.  * DoSCSIExecIO.c
  4.  * Copyright © 1992-93 Apple Computer Inc. All Rights Reserved.
  5.  *
  6.  * Talk to the Macintosh SCSI Manager 4.3 using the "new" interface. This executes
  7.  * a single SCSI Command on a device using parameters from the INFO record. Note:
  8.  * this command is only used for dialog setup and always executes synchronously
  9.  * with polled I/O and no disconnect.
  10.  *
  11.  * Calling Sequence:
  12.  *        OSErr                DoSCSISynchronousIO(
  13.  *                InfoPtr            infoPtr,
  14.  *                SCSI_CommandPtr    commandPtr,
  15.  *                unsigned long    scsiFlags,
  16.  *                Ptr                bufferPtr,
  17.  *                unsigned long    transferLength
  18.  *            );
  19.  * The following information is taken from the InfoRecord:
  20.  *                ScsiCmdBlock    *pb                -- the Scsi Command block
  21.  *                unsigned long    pbSize            -- the size of the command block
  22.  *                ProcPtr            ioCompletion    -- NULL for synch, else asynch
  23.  *                DeviceIdent        deviceIdent        -- bus/target/LUN
  24.  * After completion, the following information is stored in the InfoRecord
  25.  *                unsigned short    stsByte            -- from Status phase
  26.  *                unsigned short    msgByte            -- Command Complete message
  27.  * Return codes:
  28.  *    noErr            normal
  29.  *    statusErr        Device returned "Check condition" and SCSI Manager was able
  30.  *                    to successfully issue Request Sense. There is data in the
  31.  *                    Sense Record, but you cannot assume that the original request
  32.  *                    succeeded.
  33.  *    paramErr        Could not determine the command length.
  34.  *    sc...            Other error
  35.  */
  36. #include "SCSIAsyncSample.h"
  37. #include <GestaltEqu.h>
  38. #include <Memory.h>
  39. #include <Events.h>
  40.  
  41. static void                     NextFunction(void);        /* For HoldMemory size    */
  42. static Boolean                    IsVirtualMemoryRunning(void);
  43.  
  44. OSErr
  45. DoSCSISynchronousIO(
  46.          InfoPtr                    infoPtr,
  47.         SCSI_CommandPtr            commandPtr,
  48.         unsigned long            scsiFlags,
  49.         Ptr                        bufferPtr,
  50.         unsigned long            transferLength
  51.     )
  52. {
  53.         OSErr                        status;
  54.         register short                i;
  55.         union {
  56.             SCSIAbortCommandPB        abortCommandPB;
  57.             SCSIResetBusPB            resetBusPB;
  58.             SCSIReleaseQPB            releaseQPB;
  59.         } pb;
  60.         auto void                    *vmProtectedStackBase;    /* Last local var    */
  61. #define INFO    (*infoPtr)
  62. #define PB        (*INFO.pb)
  63. /*
  64.  * These values are used to compute the size of the stack that we must hold in
  65.  * protected (non-virtual) memory. kSCSIManagerStackEstimate is an estimate.
  66.  */
  67. #define kSCSILocalVariableSize    ( \
  68.         (unsigned long) (((Ptr) &infoPtr) - ((Ptr) &vmProtectedStackBase))    \
  69.     )
  70. #define kSCSIManagerStackEstimate 512
  71. #define kSCSIProtectedStackSize (kSCSIManagerStackEstimate + kSCSILocalVariableSize)
  72.  
  73.         status = noErr;
  74.         ClearMemory((Ptr) INFO.pb, INFO.pbSize);
  75.         ClearMemory((Ptr) INFO.vmHoldInfo, sizeof INFO.vmHoldInfo);
  76.         /*
  77.          * Setup the parameter block for the user's request.
  78.          */
  79.         PB.scsiPBLength = INFO.pbSize;
  80.         PB.scsiFunctionCode = SCSIExecIO;
  81.         PB.scsiCompletion = NULL;
  82.         PB.scsiDriverStorage = (unsigned char *) infoPtr; /* for IOCompletion    */
  83.         INFO.statusByte = 0xFF;                    /* Illegal value for debugging    */
  84.         PB.scsiTimeout = INFO.completionTimeout;
  85.         PB.scsiDevice = INFO.deviceIdent;
  86.         PB.scsiCDBLength = GetSCSICDBLength(commandPtr);
  87.         if (PB.scsiCDBLength == 0) {
  88.             status = paramErr;
  89.             goto exit;
  90.         }
  91.         /*
  92.          * Copy the command block into the SCSI PB to simplify vm lockdown.
  93.          */
  94.         BlockMove(commandPtr, &PB.scsiCDB, PB.scsiCDBLength);
  95.         /*
  96.          * Specify the transfer direction, if any. scsiFlags should be one of
  97.          *    scsiDirectionIn, scsiDirectionOut, or scsiDirectionNone
  98.          */
  99.         PB.scsiFlags = scsiFlags;        /* scsiDirectionIn or scsiDirectionOut    */
  100.         if (bufferPtr == NULL || transferLength == 0)
  101.             PB.scsiFlags = scsiDirectionNone;
  102.         else {
  103.             /*
  104.              * If the user specified the transfer quantum == 1, select "polled"
  105.              * transfers, otherwise, select "blind."
  106.              */
  107.             PB.scsiTransferType = scsiTransferPolled;
  108.             PB.scsiDataPtr = (unsigned char *) bufferPtr;
  109.             PB.scsiDataLength = transferLength;
  110.             PB.scsiDataType = scsiDataBuffer;
  111.             PB.scsiHandshake[0] = 1;
  112.             PB.scsiHandshake[1] = 0;
  113.         }
  114.         PB.scsiSensePtr = (unsigned char *) &INFO.senseData;
  115.         PB.scsiSenseLength = sizeof INFO.senseData;
  116.         /*
  117.          * The SCSI Manager "freezes" the device queue after a Check Condition
  118.          * (even if AutoSense was enabled). Disable this to prevent hangs.
  119.          */
  120.         PB.scsiFlags |= (scsiDontDisconnect | scsiSIMQNoFreeze);
  121.         /*
  122.          * We are now ready to perform the operation. If virtual memory is active
  123.          * however, we must lock down all memory segments that can be potentially
  124.          * "touched" while the SCSI request is being executed. All of this is
  125.          * needed for applications. For drivers, most of the following can be
  126.          * ignored as the driver code and driver-specific resources are stored in
  127.          * the System Heap, which is always "held" in physical memory.
  128.          */
  129.         if (gVirtualMemoryEnabled) {
  130.             /*
  131.              * Virtual memory is active. Lock all of the memory segments that we
  132.              * need in "real" memory (i.e. non-paged pool) for the duration of the
  133.              * call.
  134.              */
  135.             INFO.vmHoldInfo[kVMFunction].ptr = DoSCSISynchronousIO;
  136.             INFO.vmHoldInfo[kVMFunction].size =
  137.                 (unsigned long) NextFunction - (unsigned long) DoSCSISynchronousIO;
  138.             INFO.vmHoldInfo[kVMStack].ptr = (void *)
  139.                 (((unsigned long) &vmProtectedStackBase)
  140.                 - kSCSIManagerStackEstimate);
  141.             INFO.vmHoldInfo[kVMStack].size = kSCSIProtectedStackSize;
  142.             INFO.vmHoldInfo[kVMParam].ptr = INFO.pb;
  143.             INFO.vmHoldInfo[kVMParam].size = INFO.pbSize;
  144.             if (bufferPtr != NULL) {
  145.                 INFO.vmHoldInfo[kVMBuffer].ptr = PB.scsiDataPtr;
  146.                 INFO.vmHoldInfo[kVMBuffer].size = PB.scsiDataLength;
  147.             }
  148.             INFO.vmHoldInfo[kVMSense].ptr = PB.scsiSensePtr;
  149.             INFO.vmHoldInfo[kVMSense].size = PB.scsiSenseLength;
  150.             for (i = 0; i < kVMSize; i++) {
  151.                 if (INFO.vmHoldInfo[i].ptr != NULL) {
  152.                     status = HoldMemory(
  153.                                 INFO.vmHoldInfo[i].ptr,
  154.                                 INFO.vmHoldInfo[i].size
  155.                             );
  156.                     if (status != noErr) {
  157.                         while (i < kVMSize)
  158.                             INFO.vmHoldInfo[i++].ptr = NULL;
  159.                         break;
  160.                     }
  161.                 }
  162.             }
  163.             if (status != noErr) {
  164.                 /*
  165.                  * Something failed. Unwind before exiting.
  166.                  */
  167.                 for (i = 0; i < kVMSize; i++) {
  168.                     if (INFO.vmHoldInfo[i].ptr != NULL) {
  169.                         (void) UnholdMemory(
  170.                                 INFO.vmHoldInfo[i].ptr,
  171.                                 INFO.vmHoldInfo[i].size
  172.                             );
  173.                     }
  174.                 }
  175.             }
  176.         }
  177.         /*
  178.          * Now, just call the New SCSI Manager.
  179.          */
  180.         if (status == noErr) {
  181.             status = SCSIAction((SCSI_PB *) &PB);
  182.             if (PB.scsiCompletion == NULL) {
  183.                 /*
  184.                  * Synchronous request: The following should be
  185.                  * moved to a "default" I/O Completion routine.
  186.                  */
  187.                 if (status == noErr)
  188.                     status = PB.scsiResult;
  189.                 /*
  190.                  * These should never happen.
  191.                  */
  192.                 if (status == scsiRequestInProgress) {
  193.                     CLEAR(pb.abortCommandPB);
  194.                     pb.abortCommandPB.scsiPBLength = sizeof pb.abortCommandPB;
  195.                     pb.abortCommandPB.scsiFunctionCode = SCSIAbortCommand;
  196.                     pb.abortCommandPB.scsiIOptr = INFO.pb;
  197.                     (void) SCSIAction((SCSI_PB *) &pb.abortCommandPB);
  198.                 }
  199.                 if ((PB.scsiResultFlags & scsiBusNotFree) != 0) {
  200.                     CLEAR(pb.resetBusPB);
  201.                     pb.resetBusPB.scsiPBLength = sizeof pb.resetBusPB;
  202.                     pb.resetBusPB.scsiFunctionCode = SCSIResetBus;
  203.                     (void) SCSIAction((SCSI_PB *) &pb.resetBusPB);
  204.                 }
  205.                 if ((PB.scsiResultFlags & scsiSIMQFrozen) != 0) {
  206.                     CLEAR(pb.releaseQPB);
  207.                     pb.releaseQPB.scsiPBLength = sizeof pb.releaseQPB;
  208.                     pb.releaseQPB.scsiFunctionCode = SCSIReleaseQ;
  209.                     (void) SCSIAction((SCSI_PB *) &pb.releaseQPB);
  210.                 }
  211.                 for (i = 0; i < kVMSize; i++) {
  212.                     if (INFO.vmHoldInfo[i].ptr != NULL) {
  213.                         (void) UnholdMemory(
  214.                                 INFO.vmHoldInfo[i].ptr,
  215.                                 INFO.vmHoldInfo[i].size
  216.                             );
  217.                     }
  218.                 }
  219.                 INFO.actualTransferCount =
  220.                     PB.scsiDataLength - PB.scsiDataResidual;
  221.                 if (status == scsiDataRunError
  222.                  && PB.scsiDataResidual != PB.scsiDataLength)
  223.                     status = noErr;
  224.             }
  225.         }
  226. exit:    return (status);
  227. #undef PB
  228. }
  229.  
  230. static void NextFunction(void) { }    /* Dummy function for MacSCSICommand size    */
  231.